#if !defined(THREADPOOL_H)
#define THREADPOOL_H

#include <cstdio>
#include <exception>
#include <list>
#include <pthread.h>

#include "locker.h"

/// @brief 线程池类
/// @tparam T 任务逻辑类
template <class T>
class threadpool
{
private:
    /// @brief 线程池线程总数
    int m_thread_num;
    /// @brief 线程池描述数组
    pthread_t *m_threads;
    /// @brief 请求队列中允许的最大请求数
    int m_max_requests;
    /// @brief 请求队列
    std::list<T *> m_workQueue;
    /// @brief 保护请求队列的互斥锁
    locker m_queueLocker;
    /// @brief 数据库连接池实例
    db_connection_pool *m_connPool;

    /// @brief 是否有任务需要保护
    sem m_queueStat;
    /// @brief 是否结束线程池
    bool m_stop;

public:
    /// @brief 线程池构造函数
    /// @param connPool 数据库连接池实例
    /// @param thread_num 线程池中线程数量
    /// @param max_requests 请求队列最大请求数
    threadpool(db_connection_pool *connPool, int thread_num = 8, int max_requests = 10000);

    /// @brief 线程池析构函数
    ~threadpool();

    /// @brief 往请求队列中添加任务
    /// @param request 任务类对象指针
    /// @return 添加是否成功
    bool append(T *request);

private:
    /// @brief 启动工作线程
    /// @note 其不断从工作队列中取出任务并执行
    /// @param arg 参数
    static void *worker(void *arg);

    /// @brief 启动线程池
    void run();
};

template <class T>
threadpool<T>::threadpool(db_connection_pool *connPool, int thread_num, int max_requests)
    : m_connPool(connPool), m_thread_num(thread_num), m_max_requests(max_requests), m_stop(false), m_threads(nullptr)
{
    if ((thread_num <= 0) || (max_requests <= 0))
        throw std::exception();
    m_threads = new pthread_t[m_thread_num];
    if (!m_threads)
        throw std::exception();
    // 创建thread_num个线程，并将他们设为脱离线程
    for (int i = 0; i < thread_num; ++i)
    {
        printf("Create The %dth Thread\n", i);
        // 传入worker静态函数，参数为本对象this指针
        if (pthread_create(m_threads + i, NULL, worker, this) != 0)
        {
            delete[] m_threads;
            throw std::exception();
        }
    }
}

template <class T>
threadpool<T>::~threadpool()
{
    delete[] m_threads;
    m_stop = true;
}

template <class T>
bool threadpool<T>::append(T *request)
{
    // 共享队列务必加锁
    m_queueLocker.lock();
    if (m_workQueue.size() > m_max_requests)
    {
        m_queueLocker.unlock();
        return false;
    }

    m_workQueue.push_back(request);
    m_queueLocker.unlock();
    m_queueStat.post();
    return true;
}

template <class T>
void *threadpool<T>::worker(void *arg)
{
    threadpool *pool = (threadpool *)arg;
    pool->run();
    return pool;
}

template <class T>
void threadpool<T>::run()
{
    while (!m_stop)
    {
        m_queueStat.wait();
        m_queueLocker.lock();
        if (m_workQueue.empty())
        {
            m_queueLocker.unlock();
            continue;
        }
        T *request = m_workQueue.front();
        m_workQueue.pop_front();
        m_queueLocker.unlock();
        if (!request)
            continue;

        connRAII mysqlconn(&request->mysql_conn, m_connPool);

        request->process();
    }
}

#endif // THREADPOOL_H
